from utils.basic_function import *
from utils.database_table import Similarity


class DanglingTool(PreprocessingTool):
    def __init__(self, table, tolerance, delete_dangle_threshold, check_dangle_threshold,
                 delete_isolate_threshold, check_isolate_threshold):
        """

        Args:
            table: 要处理的表
            tolerance: 容差，距离小于tolerance视为同一个点
            delete_dangle_threshold: 悬挂线小于此值直接删除
            check_dangle_threshold: 悬挂线大于delete_dangle_threshold，小于此值，人工判断是否删除
            delete_isolate_threshold: 孤立线小于此值直接删除
            check_isolate_threshold: 孤立线大于delete_dangle_threshold，小于此值，人工判断是否删除
        """
        super(DanglingTool, self).__init__(table)
        self.tolerance = tolerance
        self.delete_dangle_threshold = delete_dangle_threshold
        self.check_dangle_threshold = check_dangle_threshold
        self.delete_isolate_threshold = delete_isolate_threshold  # 孤立线
        self.check_isolate_threshold = check_isolate_threshold
        self.check_dangle_list = []
        self.check_isolate_list = []

    def remove_dangling_table(self):
        pk_col = self.table.pk
        max_len = max(self.check_isolate_threshold, self.check_dangle_threshold)
        gdf = geopd.read_postgis(f"""select {pk_col}, {self.table.geom} from {self.table.name} 
                                 where {self.table.length} < {max_len}
                                 order by {pk_col} asc""", conn,
                                 geom_col=self.table.geom)
        for idx in gdf.index:
            pk = gdf.loc[idx, pk_col]
            print(pk)
            geom = gdf.loc[idx, self.table.geom]
            length = geom.length
            dangle_type = self.detect_dangling(geom)
            if dangle_type == "no":
                continue
            if dangle_type == "st" or dangle_type == "ed":
                if length < self.delete_dangle_threshold:
                    self.table.delete_by_attr(pk_col, pk, auto_commit=True)  # 删除悬挂
                elif length < self.check_dangle_threshold:
                    self.check_dangle_list.append(pk)
            else:  # 孤立
                if length < self.delete_isolate_threshold:
                    self.table.delete_by_attr(pk_col, pk, auto_commit=True)  # 删除孤立
                elif length < self.check_isolate_threshold:
                    self.check_isolate_list.append(pk)

    def reset_dangling(self, max_len, rclass):
        gdf = geopd.read_postgis(f"""
            select {self.table.pk}, {self.table.geom} from {self.table.name}
            where {self.table.length} < {max_len} and {self.table.match_road} is not null
            order by {self.table.length} asc
            """, conn, geom_col=self.table.geom)
        for idx in gdf.index:
            pk = gdf.loc[idx, self.table.pk]
            geom = gdf.loc[idx, self.table.geom]
            flag = self.detect_dangling(geom, and_where=f"and substring({self.table.match_road},1,1)='{rclass}'")
            if flag == "no":
                continue
            init_cols = {self.table.match_road: None}
            for col in Similarity.similarity_attrs():
                init_cols.update({col: None})
            self.table.update_attr(self.table.pk, pk, init_cols)

    def detect_dangling(self, geom, and_where=""):
        st_pt = Point(geom.coords[0])
        ed_pt = Point(geom.coords[-1])
        # 计算st的度（包括自身）
        st_deg = self.table.buffer_nodes(st_pt, self.tolerance, and_where=and_where).shape[0]
        # 计算ed的度
        ed_deg = self.table.buffer_nodes(ed_pt, self.tolerance, and_where=and_where).shape[0]
        if st_deg == 1 and ed_deg == 1:  # 孤立
            return "all"
        elif st_deg == 1 and ed_deg >= 3:
            return "ed"
        elif ed_deg == 1 and st_deg >= 3:
            return "st"
        else:
            return "no"
